import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:matuo/ble/util/UUIDUtils.dart';

import '../callback/GattCallback.dart';
import '../utils/Logcat.dart';

class ConnectManager {
  final GattCallback _gattCallback;
  late BluetoothCharacteristic? _writeCharacteristic = null;
  bool isConnecting = false;

  ConnectManager(this._gattCallback);

  //2.连接
  Future<void> connect(BluetoothDevice device) async {
    isConnecting = true;
    Logcat.instance.d("2.开始连接 >>>>>>name: ${device.name}");
    await device.connect();
    Logcat.instance.d("连接成功 >>>>>>name: ${device.name}");
    _discoverServices(device);
  }

  //3.发现服务
  Future<void> _discoverServices(BluetoothDevice device) async {
    Logcat.instance.d("3.开始发现服务 >>>>>>name: ${device.name}");
    List<BluetoothService> services = await device.discoverServices();
    Logcat.instance.d("发现服务成功 >>>>>>name: ${device.name}");
    _handlerServices(device, services); //遍历服务列表，找出指定服务
    isConnecting = false;
  }

  //3.1遍历服务列表，找出指定服务
  void _handlerServices(
      BluetoothDevice device, List<BluetoothService> services) {
    services.forEach((sItem) {
      String sUuid = sItem.uuid.toString();
      if (sUuid == UuidUtils.SET_MODE_SERVICE_UUID.toString()) {
        //找到设置模式的服务
        Logcat.instance.d(
            "4.找到设置模式的服务 >>>>>>name: ${device.name}  serviceGuid: ${UuidUtils.SET_MODE_SERVICE_UUID.toString()}");
        _readCharacteristics(device, sItem); //读取特征值
      } else if (sUuid == UuidUtils.WRITE_DATA_SERVICE_UUID.toString()) {
        //找到写数据的服务
        Logcat.instance.d(
            "4.找到写数据的服务 >>>>>>name: ${device.name}  serviceGuid: ${UuidUtils.WRITE_DATA_SERVICE_UUID.toString()}");
        _readCharacteristics(device, sItem); //读取特征值
      }
    });
  }

  //4.读取特征值(读出设置模式与写数据的特征值)
  Future<void> _readCharacteristics(
      BluetoothDevice device, BluetoothService service) async {
    var characteristics = service.characteristics;
    for (BluetoothCharacteristic cItem in characteristics) {
      String cUuid = cItem.uuid.toString();
      if (cUuid == UuidUtils.SET_MODE_CHARACTERISTIC_UUID.toString()) {
        //找到设置模式的特征值
        Logcat.instance.d(
            "4.0.找到设置模式的特征值 >>>>>>name: ${device.name}  characteristicUUID: ${UuidUtils.SET_MODE_CHARACTERISTIC_UUID.toString()}");
        _requestMtu(device); //设置MTU
        _setNotificationMode(device, cItem); //设置为Notification模式(设备主动给手机发数据)
      } else if (cUuid ==
          UuidUtils.BIG_FILE_TRANSFER_CHARACTERISTIC_WRITE_UUID.toString()) {
        //找到写数据的特征值
        Logcat.instance.d(
            "4.0.找到写数据的特征值 >>>>>>name: ${device.name}  characteristicUUID: ${UuidUtils.BIG_FILE_TRANSFER_CHARACTERISTIC_WRITE_UUID.toString()}");
        _writeCharacteristic = cItem; //保存写数据的征值
      }
    }
  }

  //4.1.设置MTU
  Future<void> _requestMtu(BluetoothDevice device) async {
    final mtu = await device.mtu.first;
    Logcat.instance.d("4.1.当前mtu: $mtu 请求设置mtu为512 >>>>>>name: ${device.name}");
    await device.requestMtu(512);
  }

  //4.2.设置为Notification模式(设备主动给手机发数据)，Indication模式需要手机读设备的数据
  Future<void> _setNotificationMode(
      BluetoothDevice device, BluetoothCharacteristic cItem) async {
    Logcat.instance.d("4.2.设置为通知模式 >>>>>>name: ${device.name}");
    await cItem.setNotifyValue(true); //为指定特征的值设置通知
    cItem.value.listen((value) {
      if (value == null || value.isEmpty) return;
      Logcat.instance.d("接收数据 >>>>>>name: ${device.name}  value: $value");

      _gattCallback.onRead(); //回调外部，返回设备发送的数据
    });
    var descriptors = cItem.descriptors;
    for (BluetoothDescriptor dItem in descriptors) {
      if (dItem.uuid.toString() ==
          UuidUtils.SET_MODE_DESCRIPTOR_UUID.toString()) {
        //找到设置模式的descriptor
        Logcat.instance.d("发送Notification模式给设备 >>>>>>name: ${device.name}");
        dItem.write(UuidUtils.ENABLE_NOTIFICATION_VALUE); //发送Notification模式给设备
        return;
      }
    }
  }

  //发送指令到设备
  Future<void> writeCommand(List<int> data) async {
    await _writeCharacteristic?.write(data);
  }

  //断开连接
  void disconnect(BluetoothDevice device) {
    Logcat.instance.d("断开连接 >>>>>>name: ${device.name}");
    device.disconnect(); //关闭连接
    _gattCallback.onDisconnect(); //连接失败回调
  }
}
